class Dep { // 一个依赖收集类，一个依赖的集合
  constructor () {
    this.subs = [] // 用来存放Watcher对象的数组
  }

  addSub (sub) { // 在subs中添加一个Watcher对象
    this.subs.push(sub)
  }

  removeSub (sub) { // 从subs中删除一个Watcher对象
    remove(this.subs, sub)
  }

  notify () { // 通知所有Watcher对象更新视图
    const subs = this.subs.slice()
    for (let i = 0, l = subs.length; i < l; i++) {
      subs[i].updte()
    }
  }
}

function remove (arr, item) {
  if (arr.length) {
    const index = arr.indexOf(item)
    if (index > -1) {
      return arr.splice(index, 1)
    }
  }
}
// 这里并不是源码的全部内容
class Watcher {
  constructor (vm, expOrFn, cb, options) {
    this.cb = cb;
    this.vm = vm; // 当前Vue实例
    // 这里不理解
    this.getter = parsePath(expOrFn)
    this.value = this.get()
  }

  get () {
    window.target = this;
    const vm = this.vm
    let value = this.getter.call(vm, vm)
    window.target = undefined;
    return value
  }

  update () { // 更新视图的方法
    const oldValue = this.value
    this.value = this.get()
    this.cb.call(this.vm, this.value, oldValue)
  }
}

/**
 * Parse simple path.
 * 把一个形如'data.a.b.c'的字符串路径所表示的值，从真实的data对象中取出来
 * 例如：
 * data = {a:{b:{c:2}}}
 * parsePath('a.b.c')(data)  // 2
 */
const bailRE = /[^\w.$]/
export function parsePath (path) {
  if (bailRE.test(path)) {
    return
  }
  const segments = path.split('.')
  return function (obj) {
    for (let i = 0; i < segments.length; i++) {
      if (!obj) return
      obj = obj[segments[i]]
    }
    return obj
  }
}

class Vue {
  constructor (options) {
    this._data = options._data;
    observe(this._data, options.render);
    // 新建一个Watcher观察者对象
    let watcher = new Watcher(this,); // 这时候Dep.target会指向这个Watcher对象
    // 在这里模拟render的过程，为了触发test属性的get函数
    console.log('render~', this._data.test)
  }
}

function defineReactive (obj, key, val, cb) {
  const dep = new Dep(); // 一个Dep类对象
  Object.defineProperty(obj, key, {
    enumerable: true,
    configurable: true,
    get: () => {
      if (Dep.target) { // Dep.target 就是当前的Watcher对象
        dep.addSub(Dep.target) // 存入到dep的subs中
      }
    },
    set: newVal => { // 在set的时候触发dep的notify来通知所有的watcher对象更新视图
      dep.notify();
    }
  })
}

Dep.target = null;